import pygame
from pygame.locals import *


class Gui:
   """Description:
       The primary control class for all gui events and objects.
       
      Useage:
       import pygame
       from Gui import *
       gui = Gui()
       font = pygame.font.get_default_font()
       window = Window((30, 30, 350, 250), 'Test Window', font)
       button = Button((280, 230, 60, 18), "Button", font, 12)
       button.onClick.append(on_test_btn_click)
       window.add(button)
       gui.add(window)
       
       while True:
         gui.update()
         gui.draw()
         pygame.display.flip()
   """
   def __init__(self):
      """ List of Widgets, the objects in this list will be drawn and updated until 
          removed from the list. """
      self._widgets = []
      self._ready = 1
      self._focus = None
      self._dragging = None
      self._drag_count = 0

   def draw(self):
      """ Should be called on every loop that draws to your screen. This function draws 
          all of the Widgets in the list. Objects that can contain children render the
          children themselves. """
      for obj in self._widgets:
         obj.draw()
         
   # 
   def add(self, Widget_):
      """ Adds a Widget to the current list of objects to be rendered and updated"""
      self._widgets.append(Widget_)
   
   def update(self):
      events_not_used = []
      """Should be called every loop that you wish to capture mouse and keyboard events for 
         use with the gui.
         
         TODO: Plenty to be done on the update loop of the gui. I think that the hover events 
         should be called here. Also a good place to see if the content in a window has been 
         changed eg. Should also checks to see if an object should remove itself """
      if self._dragging:
         if not pygame.mouse.get_pressed()[0]:
            print "mouse not pressed, so dropping the drag function"
            self._dragging = None
      events = pygame.event.get()
      for event in events:
         if event.type == MOUSEBUTTONDOWN:
            clicked = self.getClick(event.pos)
            if clicked:
               self._focus = clicked
               if clicked.can_drag:
                  self._dragging = clicked
            else:
               print event
               print "putting an event back on the stack since it wasnt used"
               events_not_used.append(event)
         elif event.type == MOUSEMOTION:
            if self._dragging:
               self._dragging.move(event.rel)
               self._drag_count += (abs(event.rel[0])+abs(event.rel[1]))
         elif event.type == MOUSEBUTTONUP:
            if self._dragging:
               self._dragging = None
               self._drag_count = 0
            else:
               clicked = self.getClick(event.pos)
               self._drag_count = 0
         else:
            print event
            print "putting an event back on the stack since it wasnt used"
            events_not_used.append(event)
      for e in events_not_used:
         pygame.event.post(e)
   
   def getClick(self, loc):
      """ Returns the Widget that is at screen location loc. 
      
          TODO: should change the name of this function to better represent what it does. 
          Can be used to see what the mouse is hovering over as well. 
          
          TODO: This still needs to take into account what window is on top of the list.
          At the moment it gets fuzzy when clicking on overlapping windows
      """
      x_ = loc[0]
      y_ = loc[1]
      finalObj = None
      for obj in self._widgets:
         if obj.children:
            for child in obj.children:
               if x_ >= child.get_x(): 
                  if x_ <= (child.get_x() + child.rect.w):
                     if y_ >= child.get_y(): 
                        if y_ <= child.get_y() + child.rect.h:
                           return child               
         if x_ >= obj.get_x(): 
            if x_ <= (obj.get_x() + obj.rect.w):
               if y_ >= obj.get_y(): 
                  if y_ <= obj.get_y() + obj.rect.h:
                     finalObj = obj
      return finalObj

   def _char_input(self, char):
      """Takes care of characters that are input when the gui is actively processing the
         event queue.
         
         TODO: This needs to play nice with shift and filter any chars that produce a 
         glyph. I also assume that this is not safe at all.
      """
      if self._focus:
         print "have widget in focus"
         if hasattr(self._focus, 'add_char'):
            self._focus.add_char(char)
            
   def get_rects(self):
      """Returns a list of rects of _ONLY_ the parent objects eg. windows.
      """
      rects = []
      for g in self._widgets:
         rects.append(g.rect)
      return rects
      
   def draw_debug(self):
      """Draws a debugging window that displays misc information on the state of the gui
         engine.
      """
      font = pygame.font.Font(pygame.font.get_default_font(), 14)
      r = pygame.Rect(300,20,0,0)
      screen = pygame.display.get_surface()
      surfaces = []
      surfaces.append(font.render('Hovering: ' + str(self.getClick(pygame.mouse.get_pos())), 1, (255,255,255)))
      surfaces.append(font.render('Dragging: ' + str(self._dragging), 1, (255,255,255)))
      surfaces.append(font.render('   Distance: ' + str(self._drag_count), 1, (255,255,255)))
      surfaces.append(font.render('Top Window: '+ str(self._widgets[-1]), 1, (255,255,255)))
      surfaces.append(font.render('Focus: ' + str(self._focus), 1, (255,255,255)))
      line = 0
      for s in surfaces:
         screen.blit(s, 
            (r.x,
               r.y + line * s.get_height(),
               r.w, 
               r.h))
         line +=1
   def _set_focus(self):
      print self._widgets